package com.mumux.framework.ioc.core;

import com.google.common.collect.Lists;
import com.mumux.framework.ioc.annotation.Autowired;
import com.mumux.framework.ioc.annotation.Component;
import com.mumux.framework.ioc.annotation.Service;
import com.mumux.framework.ioc.bean.BeanDefinition;
import com.mumux.framework.ioc.utils.ClassUtils;
import com.mumux.framework.ioc.utils.ReflectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

@Slf4j
public class AnnotationApplicationContext  extends BeanFactoryImpl{

    private String scanPath;

    public AnnotationApplicationContext(String scanPath) {
        this.scanPath = scanPath;
    }

    public void init(){
        loadAnnotation();
        try {
            attriAssign();
        } catch (Exception e) {
            log.error("Aotowire注入失败");

        }
    }

    /**
     * 获取包下的所有类名
     * @param
     * @return
     */
    public  List<String> getClassNames(){
        // 第一个class类的集合
        List<String> classNames = new ArrayList<String>();
        // 是否循环迭代
        boolean recursive = true;
        // 获取包的名字 并进行替换
        String packageDirName = scanPath.replace('.', '/');
        // 定义一个枚举的集合 并进行循环来处理这个目录下的things
        Enumeration<URL> dirs;
        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            // 循环迭代下去
            while (dirs.hasMoreElements()) {
                // 获取下一个元素
                URL url = dirs.nextElement();
                // 得到协议的名称
                String protocol = url.getProtocol();
                // 如果是以文件的形式保存在服务器上
                if ("file".equals(protocol)) {
                    // 获取包的物理路径
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    // 以文件的方式扫描整个包下的文件 并添加到集合中
                    scanClassesInPackageByFile(scanPath, filePath, recursive, classNames);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return classNames;

    }

    /**
     * 以文件的形式来获取包下的所有Class
     *
     * @param scanPath
     * @param packagePath
     * @param recursive
     * @param classNames
     */
    public static void scanClassesInPackageByFile(String scanPath, String packagePath, final boolean recursive,
                                                        List<String> classNames) {
        // 获取此包的目录 建立一个File
        File dir = new File(packagePath);
        // 如果不存在或者 也不是目录就直接返回
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        // 如果存在 就获取包下的所有文件 包括目录
        File[] dirfiles = dir.listFiles(new FileFilter() {
            // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
            public boolean accept(File file) {
                return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
            }
        });
        // 循环所有文件
        for (File file : dirfiles) {
            // 如果是目录 则继续扫描
            if (file.isDirectory()) {
                scanClassesInPackageByFile(scanPath + "." + file.getName(), file.getAbsolutePath(), recursive,
                        classNames);
            } else {
                // 如果是java类文件 去掉后面的.class 只留下类名
                String className = file.getName().substring(0, file.getName().length() - 6);

                    // 添加到集合中去
                classNames.add(scanPath + '.' + className);

            }
        }
    }


    /**
     * 加载指定包路径下有service的类，并且注册
     */
    private void loadAnnotation(){
        List<String> classNames = getClassNames();
        List<BeanDefinition> beanDefinitions = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(classNames)){
            classNames.forEach(clsName ->{
                Class<?> clazz = ClassUtils.loadClass(clsName);
                Service service = clazz.getAnnotation(Service.class);
                Component component = clazz.getAnnotation(Component.class);
                String beanId = null;
                if (service != null) {
                    // beanId 类名小写
                    beanId = service.value();

                }else if (component != null){
                    beanId = component.value();
                }

                if (StringUtils.isEmpty(beanId)) {
                    // 获取当前类名
                    beanId = toLowerCaseFirstOne(clazz.getSimpleName());
                }
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setClassName(clsName);
                beanDefinition.setName(beanId);
                beanDefinitions.add(beanDefinition);
            });
        }

        if (CollectionUtils.isNotEmpty(beanDefinitions)){
            for (BeanDefinition beanDefinition : beanDefinitions) {
                registerBean(beanDefinition.getName(), beanDefinition);
                try {
                    getBean(beanDefinition.getName());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    }

    // 首字母转小写
    private  String toLowerCaseFirstOne(String s) {
        if (Character.isLowerCase(s.charAt(0))) {
            return s;
        } else {
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
        }
    }




    public static void main(String[] args) {
        System.out.println(new AnnotationApplicationContext("com.mumux.framework").getClassNames().toString());
    }
}
